using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
using Microsoft.Xna.Framework.Net;
using Microsoft.Xna.Framework.Storage;


namespace xboxssbeatemup
{
    /// <summary>
    /// This is a game component that implements IUpdateable.
    /// </summary>
    public class CameraComponent : Microsoft.Xna.Framework.GameComponent
    {
        public Matrix View = Matrix.Identity;
        public Matrix Projection = Matrix.Identity;
        public Matrix Rotation = Matrix.Identity;

        public Vector3 Position = new Vector3(0.0f, 10.0f, 60.0f);
        public Vector3 GameplayPosition = new Vector3(0.0f, 00.0f, 30.0f);
        public Vector3 FreeRangePosition = new Vector3(0.0f, 30.0f, 60.0f);
        public Vector3 TopDownPosition = new Vector3(0.0f, 200.0f, 0.0f);
        public Vector3 Direction = Vector3.Zero;
        public Vector3 reference = new Vector3(0, 0, 1);

        public float yaw = 0.0f;
        public float pitch = 0.0f;
        public float roll = 0.0f;

        public Vector3 UpVector = Vector3.Up;
        public Vector3 LookAt;

        float NearZ = 1.0f;
        float FarZ = 2000.0f;
        float FOV = 70.0f; // 45.0 is default

        public float cameraHeight = 40.0f;

        public enum ViewMode
        {
            FreeRange,
            Gameplay,
            TopDown
        }
        public ViewMode viewMode = ViewMode.TopDown;


        public CameraComponent(Game game)
            : base(game)
        {
            // TODO: Construct any child components here
        }

        /// <summary>
        /// Allows the game component to perform any initialization it needs to before starting
        /// to run.  This is where it can query for any required services and load content.
        /// </summary>
        public override void Initialize()
        {
            this.Projection = Matrix.CreatePerspectiveFieldOfView(
                MathHelper.ToRadians(FOV),
                this.Game.GraphicsDevice.Viewport.AspectRatio,
                this.NearZ,
                this.FarZ);

            base.Initialize();
        }

        /// <summary>
        /// Allows the game component to update itself.
        /// </summary>
        /// <param name="gameTime">Provides a snapshot of timing values.</param>
        public override void Update(GameTime gameTime)
        {
            switch (viewMode)
            {
                case ViewMode.FreeRange:
                    Position = FreeRangePosition;
                    break;
                case ViewMode.Gameplay:
                    UpVector = Vector3.Up;
                    LookAt = ((Game1)this.Game).players[0].position;
                    //LookAt.Y *= 0.1f;
                    LookAt.Z *= 1.5f;
                    GameplayPosition.X = ((Game1)this.Game).players[0].position.X;
                    GameplayPosition.Z = ((Game1)this.Game).players[0].position.Z + 80.0f;
                    GameplayPosition.Y = ((Game1)this.Game).heightMapInfo.GetHeight(GameplayPosition) + cameraHeight;
                    Position = GameplayPosition;
                    break;
                case ViewMode.TopDown:
                    if (((Game1)this.Game).editor.mouseState.LeftButton == ButtonState.Pressed)
                    {
                        Vector3 mouseMovement = Vector3.Zero;
                        mouseMovement.X = ((Game1)this.Game).editor.mouseState.X - ((Game1)this.Game).editor.prevMouseState.X;
                        mouseMovement.Y = ((Game1)this.Game).editor.mouseState.Y - ((Game1)this.Game).editor.prevMouseState.Y;
                        TopDownPosition.X -= mouseMovement.X * (TopDownPosition.Y / 700.0f);
                        TopDownPosition.Z -= mouseMovement.Y * (TopDownPosition.Y / 700.0f);
                    }
                    float shiftMultiplier = 1.0f;
                    const float eShiftMultiplier = 15.0f;
                    if (((Game1)this.Game).editor.keyboardState.IsKeyDown(Keys.LeftShift) || ((Game1)this.Game).editor.keyboardState.IsKeyDown(Keys.RightShift))
                        shiftMultiplier = eShiftMultiplier;
                    if (((Game1)this.Game).editor.keyboardState.IsKeyDown(Keys.Subtract))
                        TopDownPosition.Y += 1.0f * shiftMultiplier;
                    if (((Game1)this.Game).editor.keyboardState.IsKeyDown(Keys.Add))
                        TopDownPosition.Y -= 1.0f * shiftMultiplier;
                    Direction = Vector3.Down;
                    UpVector = Vector3.Forward;
                    LookAt = TopDownPosition + Direction;
                    Position = TopDownPosition;
                    break;
            }
            View = Matrix.CreateLookAt(Position, LookAt, UpVector);
            
            base.Update(gameTime);
        }
    }
}